import Taro from "@tarojs/taro";
import {getGlobalData, setGlobalData} from "../../utils/globalData";

class Core{
  options={
    resource:{},//座位资源图
    partition:{},//分区座位资源图
    isPc:false,//是否PC
    isArea:false,//是否分区
    seatData:[],//座位图数据
    boxW:0,//窗体宽度
    boxH:0,//窗体高度
    boxL:0,//窗体外左边距离
    boxT:0,//窗体外顶部距离
    w:40,//单座位宽
    h:40,//单座位高
    bg:null,//背景图片
    bgWidth:0,
    bgHeight:0,
    num:18,//单个canvas最大绘制行列数
    padding:[40,40,40,40],//窗体内上下左右边距
    minMapSize:{
      w:400,
      h:300
    },
    onInitMap(){},
    onRender(){},//渲染
    onClickSeat(){},//座位点击
    onShowMinMap(){},
    onHandleShowReset(){},
  }
  data={
    originTouchData:{
      x:0,
      y:0,
      x1:0,
      y1:0
    },
    oriTransformData:{
      scale:1,
      x:0,
      y:0
    },
    center:{
      x:0,
      y:0
    },
    transformData:{
      scale:1,
      x:0,
      y:0
    },
    cols:0,//列数
    rows:0,//行数
    minScale:0.5,
    maxScale:1,
    baseScale:1,
    mouseDown:false,
    seatMap:[],
    contentW:0,
    contentH:0
  }
  constructor(options) {
    Object.assign(this.options,options)
    this.data.maxScale=this.options.boxW/750*3
    let canvasW=0
    let canvasH=0
    if(!this.options.isArea){
      Object.assign(this.data,{
        rows:this.options.seatData.length,
        cols:this.options.seatData[0].length
      })
    }
    this.data.contentW=this.options.isArea?this.options.bgWidth:this.data.cols*this.options.w
    this.data.contentH=this.options.isArea?this.options.bgHeight:this.data.rows*this.options.h
    canvasW=(this.data.contentW+this.options.padding[1]+this.options.padding[3])*this.data.maxScale
    canvasH=(this.data.contentH+this.options.padding[0]+this.options.padding[2])*this.data.maxScale

    const wMinScale=canvasW>this.options.boxW?(this.options.boxW*this.data.maxScale/canvasW):this.data.maxScale/3
    const hMinScale=canvasH>this.options.boxH?(this.options.boxH*this.data.maxScale/canvasH):this.data.maxScale/3
    this.data.minScale=wMinScale<hMinScale?wMinScale:hMinScale
    this.data.baseScale=this.data.maxScale*0.5<this.data.minScale?this.data.minScale:this.data.maxScale*0.5
    this.initMap()
    this.transform({
      scale:this.data.minScale
    })
  }
  touchInit(e){
    this.data.oriTransformData=this.data.transformData
    if(e.touches.length==1){
      Object.assign(this.data.originTouchData,{
        x:e.touches[0].clientX,
        y:e.touches[0].clientY,
      })
    }else{
      this.data.center={
        x:(e.touches[1].clientX+e.touches[0].clientX)/2,
        y:(e.touches[1].clientY+e.touches[0].clientY)/2,
      }
      Object.assign(this.data.originTouchData,{
        x:e.touches[0].clientX,
        y:e.touches[0].clientY,
        x1:e.touches[1].clientX,
        y1:e.touches[1].clientY,
      })
    }
  }
  mousedownEvent(e){
    if(this.options.isPc){
      this.data.mouseDown=true
      console.log('mousedownEvent')
      this.touchStartEvent({
        touches:[e]
      })
    }
  }
  mousemoveEvent(e){
    if(this.options.isPc&&this.data.mouseDown){
      this.touchMoveEvent({
        touches:[e]
      },true)
    }
  }
  mouseupEvent(){
    if(this.options.isPc){
      this.data.mouseDown=false
      if(this.data.tap){
        this.touchEndEvent({
          touches:[]
        })
      }
    }
  }
  reset(){
    this.data.oriTransformData=this.data.transformData
    this.transform({
      scale:this.data.minScale/this.data.transformData.scale
    })
  }
  touchStartEvent(e){
    if(e.touches.length<3){
      this.touchInit(e)
    }
    this.data.tap=e.touches.length==1?e:null
    console.log('touchStartEvent')
  }
  touchMoveEvent(e,isMouseEvent){
    if(!isMouseEvent){
      this.data.tap=null
    }
    if(e.touches.length<3){
      this.options.onShowMinMap(true)
      if(e.touches.length==1){//移动
        if(isMouseEvent&&(Math.abs(e.touches[0].clientX-this.data.originTouchData.x)>10||Math.abs(e.touches[0].clientY-this.data.originTouchData.y)>10)){
          this.data.tap=null
        }
        this.transform({
          x:(e.touches[0].clientX-this.data.originTouchData.x),
          y:(e.touches[0].clientY-this.data.originTouchData.y),
        })
      }else{//缩放
        const oriDistance=Math.hypot(this.data.originTouchData.x1-this.data.originTouchData.x, this.data.originTouchData.y1-this.data.originTouchData.y)
        const curDistance=Math.hypot(e.touches[1].clientX-e.touches[0].clientX, e.touches[1].clientY-e.touches[0].clientY)
        let scale=curDistance/oriDistance
        if(scale*this.data.oriTransformData.scale<this.data.minScale){
          scale=this.data.minScale/this.data.oriTransformData.scale
        }else if(scale*this.data.oriTransformData.scale>this.data.maxScale){
          scale=this.data.maxScale/this.data.oriTransformData.scale
        }
        const x=(this.data.center.x-this.data.oriTransformData.x-this.options.boxL)*(1-scale)
        const y=(this.data.center.y-this.data.oriTransformData.y-this.options.boxT)*(1-scale)
        this.transform({
          x,
          y,
          scale
        })
      }
    }
  }
  touchEndEvent(e){
    if(this.data.tap){
      const tap=this.data.tap
      this.data.tap=null
      this.tapEvent(tap)
    }
    if(e.touches.length<3&&e.touches.length){
      this.touchInit(e)
    }
    this.options.onShowMinMap(false)
  }
  transform(data){
    const oriTransformData=this.data.oriTransformData
    const transformData={
      x:oriTransformData.x+(data.x||0),
      y:oriTransformData.y+(data.y||0),
      scale:oriTransformData.scale*(data.scale||1)
    }
    const w=(this.data.contentW+this.options.padding[1]+this.options.padding[3])*transformData.scale
    const h=(this.data.contentH+this.options.padding[0]+this.options.padding[2])*transformData.scale
    if(w<this.options.boxW){
      transformData.x=(this.options.boxW-w)/2
    }else{
      transformData.x=transformData.x>0?0:transformData.x
      const min=this.options.boxW-w
      if(transformData.x<min){
        transformData.x=min
      }
    }
    if(h<this.options.boxH){
      transformData.y=(this.options.boxH-h)/2
    }else{
      transformData.y=transformData.y>0?0:transformData.y
      const min=this.options.boxH-h
      if(transformData.y<min){
        transformData.y=min
      }
    }
    this.data.transformData=transformData
    this.options.onRender(this.data.transformData)
    this.options.onHandleShowReset(this.data.transformData.scale>this.data.minScale?(new Date().getTime()):0)
  }
  rotatePoint(ptSrc, ptRotationCenter, angle) {
    const x = ptRotationCenter.x + (ptSrc.x - ptRotationCenter.x) * Math.cos(angle * Math.PI / 180) - (ptSrc.y - ptRotationCenter.y) * Math.sin(angle * Math.PI / 180);
    const y = ptRotationCenter.y + (ptSrc.x - ptRotationCenter.x) * Math.sin(angle * Math.PI / 180) + (ptSrc.y - ptRotationCenter.y) * Math.cos(angle * Math.PI / 180);
    return {x,y}
  }
  getSeatPos(x,y){
    let seat=null
    let pos={}
    if(this.options.isArea){
      for(let area of this.options.seatData){
        const point=this.rotatePoint({x,y},area,-1*area.rotation)
        if(point.x-area.x>0&&point.x-area.x-(area.cols*this.options.w)<0&&point.y-area.y>0&&point.y-area.y-(area.rows*this.options.h)<0){
          const col=Math.floor((point.x-area.x)/this.options.w)
          const row=Math.floor((point.y-area.y)/this.options.h)
          seat = area.sseat[row][col]
          pos={
            row,
            col
          }
          break
        }
      }
    }else{
      pos={
        row:Math.floor(y/this.options.h),
        col:Math.floor(x/this.options.w),
      }
      seat=this.options.seatData[pos.row][pos.col]
    }
    return {
      seat,
      pos
    }
  }
  tapEvent(tap){
    const tx=tap.touches[0].pageX-this.options.boxL-this.data.transformData.x-(this.options.padding[0]*this.data.transformData.scale)
    const ty=tap.touches[0].clientY-this.options.boxT-this.data.transformData.y-(this.options.padding[3]*this.data.transformData.scale)
    const contentW=this.data.contentW*this.data.transformData.scale
    const contentH=this.data.contentH*this.data.transformData.scale
    if(tx>0&&ty>0&&tx<contentW&&ty<contentH){
      const seatInfo=this.getSeatPos(tx/this.data.transformData.scale,ty/this.data.transformData.scale)
      console.log({seatInfo})
      if(seatInfo.seat){
        if(this.data.transformData.scale<=this.data.minScale){
          const scale=this.data.baseScale/this.data.oriTransformData.scale
          let x=(tap.touches[0].clientX-this.data.oriTransformData.x-this.options.boxL)*(1-scale)
          let y=(tap.touches[0].clientY-this.data.oriTransformData.y-this.options.boxT)*(1-scale)
          x+=this.options.boxL+this.options.boxW/2-tap.touches[0].clientX
          y+=this.options.boxT+this.options.boxH/2-tap.touches[0].clientY
          this.transform({
            x,
            y,
            scale
          })
        }
        this.options.onClickSeat(seatInfo.seat,seatInfo.pos)
      }
    }
  }
  async initMap(){
    Taro.showLoading({title:'加载中...'})
    const imgResource = await this.getResource()
    let seatMap=[]
    if(this.options.isArea){
      seatMap=this.options.seatData.map(area=>{
        const w=area.sseat[0].length*this.options.w
        const h=area.sseat.length*this.options.h
        return {
          x:area.x,
          y:area.y,
          w,
          h,
          style:`width:${w}px;height:${h}px`
        }
      })
    }else{
      const mapRows=Math.ceil(this.data.rows/this.options.num)
      const mapCols=Math.ceil(this.data.cols/this.options.num)
      for(let j=0;j<mapRows;j++){
        const rows=(j+1)*this.options.num<=this.data.rows?this.options.num:this.data.rows%this.options.num
        const height=this.options.h*rows
        let rowWidth=0
        const parts=[]
        for(let i=0;i<mapCols;i++){
          const cols=(i+1)*this.options.num<=this.data.cols?this.options.num:this.data.cols%this.options.num
          const width=this.options.w*cols
          rowWidth+=width
          parts.push({
            x:i*this.options.num,
            y:j*this.options.num,
            rows,
            cols,
            width,
            height,
            style:`width:${width}px;height:${height}px`,
          })
        }
        seatMap.push({
          parts,
          style:`width:${rowWidth}px;height:${height}px`
        })
      }
    }
    let cateArr = null
    if(this.options.catelist?.length) cateArr = await this.getCateArr()
    this.options.onInitMap({
      seatMap,
      imgResource,
      cateArr,
      ...this.options,
      resource:this.options.resource,
      transformData:this.data.transformData,
      cols:this.data.cols,
      rows:this.data.rows,
      width:this.data.contentW+this.options.padding[1]+this.options.padding[3],
      height:this.data.contentH+this.options.padding[0]+this.options.padding[2],
      seatSize:{
        w:this.options.w,
        h:this.options.h,
      }
    })
    Taro.hideLoading()
  }
  getResource(){
    return new Promise(resolve => {
      let num=0
      const resource={}
      if(process.env.TARO_ENV == 'tt'){
        setTimeout(() => {
          const query = tt.createSelectorQuery();
          query.select("#canvasNode").node().exec((res) => {
            const globalResource=getGlobalData('seatBase64Resource')||{}
            for (const index in this.options.resource) {
              const img=res[0].node.createImage()
              const src=this.options.resource[index]
              if(globalResource[index]){
                resource[index]=globalResource[index]
                if(++num==Object.keys(this.options.resource).length){
                  resolve(resource)
                }
              }else{
                img.onload=()=>{
                  resource[index]=img
                  globalResource[index]=img
                  setGlobalData('seatBase64Resource',globalResource)
                  if(++num==Object.keys(this.options.resource).length){
                    resolve(resource)
                  }
                }
                img.src=src
              }
            }
          });
        }, 500);
        return;
      }
      if(process.env.TARO_ENV == 'weapp'){
        let canvas = Taro.createOffscreenCanvas({type:'2d'})
        const globalResource=getGlobalData('seatBase64Resource')||{}
        for (const index in this.options.resource) {
          const img=canvas.createImage()
          const src=this.options.resource[index]
          if(globalResource[index]){
            resource[index]=globalResource[index]
            if(++num==Object.keys(this.options.resource).length){
              resolve(resource)
            }
          }else{
            img.onload=()=>{
              resource[index]=img
              globalResource[index]=img
              setGlobalData('seatBase64Resource',globalResource)
              if(++num==Object.keys(this.options.resource).length){
                resolve(resource)
              }
            }
            img.src=src
          }
        }
      }
      if(process.env.TARO_ENV == 'h5'){
        const globalResource=getGlobalData('seatBase64Resource')||{}
        for (const index in this.options.resource) {
          const img=new Image()
          const src=this.options.resource[index]
          if(globalResource[index]){
            resource[index]=globalResource[index]
            if(++num==Object.keys(this.options.resource).length){
              resolve(resource)
            }
          }else{
            img.onload=()=>{
              resource[index]=img
              globalResource[index]=img
              setGlobalData('seatBase64Resource',globalResource)
              if(++num==Object.keys(this.options.resource).length){
                resolve(resource)
              }
            }
            img.src=src
          }
        }
      }
    })
  }
  getCateArr(){
    return new Promise(resolve => {
      let num=0
      const resource={}
      if(process.env.TARO_ENV == 'tt'){
        setTimeout(() => {
          const query = tt.createSelectorQuery();
          query.select("#canvasNode").node().exec((res) => {
            this.options.catelist.forEach(item=>{
              const img=res[0].node.createImage()
              img.src=`${item.url}?r=`+new Date().getTime()
              img.onload=()=>{
                resource[item.area || item.priceId]=img
                if(++num==this.options.catelist?.length){
                  resolve(resource)
                }
              }
            })
          });
        }, 500);
        return;
      }
      if(process.env.TARO_ENV == 'weapp'){
        let canvas = Taro.createOffscreenCanvas({type:'2d'})
        this.options.catelist.forEach(item=>{
          const img=canvas.createImage()
          img.crossOrigin = 'Anonymous'
          img.src=`${item.url}?r=`+new Date().getTime()
          img.onload=()=>{
            resource[item.area || item.priceId]=img
            if(++num==this.options.catelist?.length){
              resolve(resource)
            }
          }
        })
      }
      if(process.env.TARO_ENV == 'h5'){
        this.options.catelist.forEach(item=>{
          const img=new Image()
          img.crossOrigin = 'Anonymous'
          img.src=`${item.url}?r=`+new Date().getTime()
          img.onload=()=>{
            resource[item.area || item.priceId]=img
            if(++num==this.options.catelist?.length){
              resolve(resource)
            }
          }
        })
      }
    })
  }
}
export default Core
